home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Tool Chest / Testing & Debugging / Memory Management / Xap Handles dcmd / Xap.a < prev    next >
Encoding:
Text File  |  1993-09-17  |  10.6 KB  |  252 lines  |  [TEXT/MPS ]

  1. ; Zap.a
  2. ;
  3. ;        Copyright © 1991 by Apple Computer, Inc., all rights reserved.
  4. ;
  5. ;    by     Bo3b Johnson        1/10/91
  6. ;            MS 37-DS
  7. ;        
  8. ;    This file is the assembly routines I need in order to interface to the toolbox in
  9. ;    a sensible fashion.  The OS is funky, and there is no good way to do these things
  10. ;    from Pascal or C.  The use of INLINE code is OK, but not always enough.
  11. ;    Course I hate assembly language, since I tire of knives in the back, but there often
  12. ;    is no alternative.  Only dimwits think assembly is the way to go.  Too bad so
  13. ;    many people still have the Iron-Man syndrome, instead of using their brains.
  14. ;
  15. ;    In order to fashion a good patch to NewPtr/NewHandle, I need to use PC
  16. ;    relative addressing.  The basic problem is that there is no good way to get back
  17. ;    to the dcmd globals, while the patch is executing.  Certainly you can't rely upon
  18. ;    A5, A6, or A7; and no other registers are available for use.  I could stick something
  19. ;    into AppParms, CurApName, or a number of other atrocities, but I don't own
  20. ;    any of those spots, and could quite easily end up competing with some other code
  21. ;    for the spot.  If I use PC-relative addressing to get to
  22. ;    some global information, then this becomes self-modifying code, since I will
  23. ;    change the code in this block, using a piece of code space as variable storage.  
  24. ;    This seems the most risk-free version for now, notwithstanding certain strident
  25. ;    if misguided warnings from various groups.  It's not enough to tell me not to
  26. ;    do something, you have to give me an alternative.  If you have a better alternative,
  27. ;    by all means let me know.
  28. ;
  29. ;    I patch the two traps of DisposPtr, DisposHandle; and these pieces are almost identical.  
  30. ;    The only difference really is the variable being
  31. ;    used.  The basic idea is to have one routine to save off the old address, gotten from
  32. ;    an NGetTrapAddress; and to save that into the code here, using PC-relative addressing.
  33. ;    The trap is patched by the Pascal code, and whenever it gets called, it will call here
  34. ;    to have us call through the old version of the trap.  That way it gets control before
  35. ;     the trap executes, but I still drive the old code. 
  36. ;
  37. ;    Realize that the code in this file is getting run mostly during the normal operation
  38. ;    of the Mac.  The stack is whatever the current app is using, as well as that A5 world,
  39. ;    and stack crawl.  I don't know where I'll be so, I can't rely on those things.  This
  40. ;    is very different from the code in the dcmd, where it knows the stack it is using is
  41. ;    in Macsbug, and very small.  Pieces of this code will get run a tiny bit from the dcmd,
  42. ;    since it will call here in order to get access to my global variables, the activeState.  
  43. ;
  44. ;     By the way, this file looks best if viewed in Palatino 12.
  45.  
  46.     
  47.             include        'SysErr.a'
  48.             include        'SysEqu.a'
  49.             include        'Traps.a'
  50.  
  51.             proc
  52.  
  53. ; ——————————————————————————————————————————————————————————————————————————————————————————————————
  54. ;
  55. ; Storage for the old patch addresses, used to call through once the patch code executes.
  56. ;    These are essentially globals, used by the asm code.  They are specifically not exported,
  57. ;    so that the Pascal code cannot access them directly.  There are a number of interface
  58. ;    routines I set up so that Pascal can get and set them, but has to go through this file.
  59. ;    You know, sort of object like.
  60. ;
  61. pOldDisposPtr            dc.l        0
  62. pOldDisposHandle        dc.l        0
  63.  
  64. pActive                    dc.w        0                    ; whether to watch blocks or not.
  65.  
  66.  
  67. saveEm                    reg        a0-a3/d0-d3        ; a few to keep, since I'm a patch.
  68. saveEmSize                EQU        (8*4)                ; 8 registers times 4 bytes each.
  69.  
  70.  
  71.  
  72. ; ——————————————————————————————————————————————————————————————————————————————————————————————————
  73. ; When I'm am setting up the world, I call NGetTrapAddress to get the old version
  74. ; of the traps.  I need to save that dude off so I can get back there when needed. 
  75. ; This routine is a handy interface to the high-level world, isolating this asm junk
  76. ; from the code.   All these routines are the same, just a different variable being affected.
  77. ; This hunk uses the PC-Relative addressing mode in order to get the address of the
  78. ; variable being set.  This allows the code to function without any explicit global
  79. ; space, since the code acts like globals here.
  80. ; The interface is:
  81. ;    PROCEDURE  SetOldDisposPtr (address: LongInt);
  82. ;    PROCEDURE  SetOldDisposHandle (address: LongInt);
  83.  
  84.             export        SetOldDisposPtr, SetOldDisposHandle
  85.  
  86. SetOldDisposPtr
  87.             LEA            pOldDisposPtr,A1            ; the variable to do
  88.             BRA.S        Common                    ; do common stuffing code.
  89. SetOldDisposHandle
  90.             LEA            pOldDisposHandle,A1        ; the variable 
  91. Common        
  92.             MOVE.L        (SP)+,A0                        ; get the return address.
  93.             MOVE.L        (SP)+,(A1)                    ; save it, pulling parameter too.
  94.             JMP            (A0)                            ; it's saved, return to high-level.
  95.  
  96.  
  97. ; ——————————————————————————————————————————————————————————————————————————————————————————————————
  98. ; Killt fer now.
  99. ;        FUNCTION    TrackActive: Boolean;    EXTERNAL;
  100.  
  101.  
  102. ; TrackActive:
  103. ;    Just return the active state as a boolean.  This is whether I am actively watching
  104. ;    and recording block addresses or not.  I always want to be able to turn it off sometimes,
  105. ;    since I want to save a given state for viewing.  
  106. ;        FUNCTION    TrackActive: Boolean;    EXTERNAL;
  107.  
  108. ;TrackActive
  109. ;            MOVE.W    pActive,4(SP)                ; stuff function result (pc-relative source).
  110. ;            RTS                                            ; and return to caller. 
  111.             
  112.  
  113. ; ——————————————————————————————————————————————————————————————————————————————————————————————————
  114. ; As part of the interface to the dcmd, I have setting routines too, to set the variables
  115. ; to a known state.  This way I don't have to put that sort of tree-based init code in 
  116. ; assembly.  I need to turn it on and off using the dcmd, so it will call here to do so.
  117. ;
  118. ;        PROCEDURE SetActive (state: Boolean);        EXTERNAL;
  119.  
  120.  
  121.             export        SetActive
  122.  
  123. ;        PROCEDURE SetActive (state: Boolean);        EXTERNAL;
  124.  
  125. SetActive
  126.             MOVE.L        (SP)+,A0                        ; the return address, for safe keeping.
  127.             LEA            pActive,A1                    ; the variable I need to set, pc-relative.
  128.             MOVE.W    (SP)+,(A1)                    ; save off the new state, clearing parameter.
  129.             JMP            (A0)                            ; and return to caller.
  130.             
  131.             
  132. ; ——————————————————————————————————————————————————————————————————————————————————————————————————
  133. ;    This is the patch code for the various pieces I patch.  This is in assembly
  134. ;     since I need to preserve registers and do some other low level jacking around. 
  135. ;    These routines are the specific code that gets called when one of the four traps is executed.
  136.  
  137. ; ——————————————————————————————————————————————————————————————————————————————————————————————————
  138. ; WatchDisposPtr:
  139. ;    This routine is my patch to DisposPtr.  I will get the size of the block, then have the block
  140. ;    stuffed into all blow up numbers.  This is a head patch, since I do my thing, then jump to
  141. ;    the old routine.  When that routine finishes, it will call RTS and go back to
  142. ;    wherever I was called from.
  143.  
  144.             export        WatchDisposPtr
  145.             
  146. WatchDisposPtr
  147.             MOVEM.L    saveEm,-(SP)                ; save registers in trap patches.
  148.  
  149.             MOVE.W    pActive,D0                    ; is it turned on to watch?
  150.             BEQ.S            CallOldDisposePtr            ; if not, skip saving.
  151.             
  152.             _GetPtrSize                                    ; find out how big the dude is.
  153.             TST.L            D0                                ; if it is not a real thing?
  154.             BLE.S            CallOldDisposePtr            ; negative or zero, skip the stomp.
  155.             
  156.             MOVE.L        A0,-(SP)                        ; block being killed, save it's address.
  157.             MOVE.L        D0,-(SP)                        ; size of the block.
  158.             
  159.             BSR.S            StompBlock                    ; go turn it into mush.
  160.             
  161. CallOldDisposePtr
  162.             MOVEM.L    (SP)+,saveEm                ; save registers in trap patches.
  163.  
  164.             MOVE.L        pOldDisposPtr,-(SP)        ; get address of old routine.
  165.             RTS                                            ; and jump there.
  166.                                                             ; when it RTSes, I'll go back to the caller.
  167.                         
  168.  
  169. ; ——————————————————————————————————————————————————————————————————————————————————————————————————
  170. ; WatchDisposHandle:
  171. ;    This routine is my patch to DisposHandle.  I get the size of the block, then call StompBlock
  172. ;    to turn it into all trashed numbers.  This is a head patch, since I do my thing, then jump to
  173. ;    the old routine.  When that routine finishes, it will call RTS and go back to
  174. ;    wherever I was called from.
  175.  
  176.             export        WatchDisposHandle
  177.             
  178. WatchDisposHandle
  179.             MOVEM.L    saveEm,-(SP)                ; save registers in trap patches.
  180.  
  181.             MOVE.W    pActive,D0                    ; is it turned on to watch?
  182.             BEQ.S            CallOldDisposeHandle    ; if not, skip saving.
  183.             
  184.             _GetHandleSize                            ; find out how big the handle is.
  185.             TST.L            D0                                ; Test to see what happened.
  186.             BLE.S            CallOldDisposeHandle    ; negative or zero, skip the stomp.
  187.  
  188.             MOVE.L        (A0),-(SP)                    ; dereference handle to pointer, as block. 
  189.             MOVE.L        D0,-(SP)                        ; pass the size to kill
  190.             
  191.             BSR.S            StompBlock                    ; and turn it into mush.
  192.             
  193. CallOldDisposeHandle
  194.             MOVEM.L    (SP)+,saveEm                ; save registers in trap patches.
  195.  
  196.             MOVE.L        pOldDisposHandle,-(SP)    ; get address of old routine.
  197.             RTS                                            ; and jump there.
  198.                                                             ; when it RTSes, I'll go back to the caller.
  199.                         
  200.                         
  201. ; ——————————————————————————————————————————————————————————————————————————————————————————————————
  202. ;
  203. ; StompBlock:
  204. ;    This is the key routine to the entire thing.  It will stuff a blow up number into the block as a 
  205. ;    repeating pattern of long words.  Right now I whap on the full long words, including the 
  206. ;    correction bytes the memory manager sets aside for things not divisible by 4.  This assumes
  207. ;    that it won't get passed a zero length object.
  208. ;
  209. ;    It trashes no registers.
  210. ;
  211. ;    Procedure StompBlock (block: Ptr; size: LongInt);
  212.  
  213. zapValue    EQU        $50FFC001                    ; funky bus error number. 
  214.  
  215.  
  216. StompBlock
  217.             MOVEM.L    A0/D0,-(SP)                    ; save registers we kill.
  218.             
  219.             MOVE.L        16(SP),A0                    ; address of block to stuff. *** use record. 
  220.             MOVE.L        12(SP),D0                        ; length of block.
  221.             
  222. ; If we got passed a zero for the pointer, something is wrong.
  223.  
  224.             CMP.L        #0,A0                            ; is it nice?
  225.             BNE.S        @1                            ; if so go ahead.
  226.             PEA            #'Nil block to Zap'
  227.             _DebugStr                                    ; else yell about it.
  228. @1            
  229. ; Find out how big the block is, in LongInt counts.  Loop for that many times, stuffing the
  230. ; LongInt number into the buffer.  I round up to the nearest long word, since the size correction
  231. ; will always be used on Mac II class machines.   This will make it work for 0 length blocks too.
  232. ; Can't use DBRA count, since that can't handle big enough blocks.
  233.  
  234.             ADDQ.L        #3,D0                            ; round up to nearest longword.
  235.             LSR.L            #2,D0                            ; divide by 4, giving Long word count.
  236. @0
  237.             MOVE.L        #zapValue,(A0)+            ; stuff the killer number
  238.             SUBQ.L        #1,D0                            ; decrement count.
  239.             BGT.S        @0                            ; if more to do, go back.
  240.             
  241.             
  242.             MOVEM.L    (SP)+,A0/D0                    ; restore registers.
  243.             MOVE.L        (SP)+,(SP)                    ; push return address over parameter
  244.             MOVE.L        (SP)+,(SP)                    ; push return address over parameter, twice.
  245.             RTS
  246.             
  247.             endproc
  248.  
  249. ; ——————————————————————————————————————————————————————————————————————————————————————————————————
  250.  
  251.             end
  252.